﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace Assets.Scripts.DL.Enemy.BaseClass.FSM {
	public class HFSM<EntityController, StateType> : EnemyState<StateType> {

		protected EntityController _controller;
		protected Dictionary<StateType, EnemyState<StateType>> _states;
		public HFSM(EntityController controller, StateType stateName) : base(stateName) {
			_controller = controller;
		}

		public override void Enter() {
			foreach (var state in _states) {
				var ret = state.Value.ConditionToSelf?.Invoke() ?? false;
				if (ret) {
					CurState = state.Value;
					//Debug.Log($"{CurState.StateName} Enter {StateName}");
					CurState.Enter();
					break;
				}
			}
			//PrintStateList();
		}

		public override void Exit() {
			CurState?.Exit();
			CurState = null;
		}

		public override void Update() {
			//CurState Update First, Then Check Transition
			//That means The Next State's Update is in the Next Frame Of Its Enter
			//So Maybe There will be less Problem in Play Anim,TNND 🐎的
			CurState.Update();
			CheckTransition();
		}

		public void InitSubStates(Dictionary<StateType, EnemyState<StateType>> state)
			=> _states = state;

		public virtual void CheckTransition() {
			if (CurState == null) {
				Debug.Log(StateName);
			}
			foreach (var item in CurState.TransitionsTo) {
				if (CheckAllFuncs(item.Value)) {
					ChangeStateTo(item.Key);
				}
			}
		}

		public virtual void ChangeStateTo(StateType state) {
			CurState.Exit();
			//Debug.Log($"CurHFSM{StateName}'s {CurState.StateName}Transition to {state}");
			CurState = _states[state];
			CurState.Enter();
		}

		private bool CheckAllFuncs(Func<bool> func) {
			var funcs = func.GetInvocationList();
			foreach (var del in funcs) {
				var function = (Func<bool>)del;
				if (!function()) {
					return false;
				}
			}
			return true;
		}

		//Debug
		protected void PrintStateList() {
			Debug.Log(GetAllStateName(this));
		}

		string GetAllStateName(EnemyState<StateType> state) {
			var ret = "";

			while (state != null) {
				ret += $"{state.StateName}->";
				state = state.CurState;
			}

			return ret;
		}
	}
}
